#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QMessageBox>
#include <QDateTime>
#include <unistd.h>
#include <QShortcut>

//构造函数
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 初始化数据库
    db = QSqlDatabase::addDatabase("QSQLITE", "mainwindow_connection");
    db.setDatabaseName("car.db");
    if (!db.open()) {
        qDebug() << "数据库打开失败" ;
    } else {
        qDebug() << "数据库打开成功";
        query = QSqlQuery(db);
    }

    mesbox_init();
    udp_init();

    connect(msgBox, &QMessageBox::buttonClicked, this, &MainWindow::warm2);
    connect(msgBox2, &QMessageBox::buttonClicked, this, &MainWindow::warm);
}

//析构函数
MainWindow::~MainWindow()
{
    delete ui;
    delete udpSocketVideo1;
    delete udpSocketVideo2;
    delete udpSocketPlate1;
    delete udpSocketPlate2;
    QSqlDatabase::removeDatabase("mainwindow_connection");
}

//=============打开菜单===============
void MainWindow::on_menu_btn_clicked()
{
    p.show();
}

//=============弹窗初始化===============
void MainWindow::mesbox_init()
{
    msgBox = new QMessageBox(
            QMessageBox::Information,
            tr("温馨提示！！！"),
            tr("本次识别确信率低于90%😭\n请确认车牌号后放行😘"),
            QMessageBox::Yes | QMessageBox::No,
            this
        );
    msgBox->setDefaultButton(QMessageBox::Yes); // 设置默认按钮
    msgBox->hide();

    msgBox2 = new QMessageBox(
            QMessageBox::Information,
            tr("温馨提示！！！"),
            tr("本次识别确信率低于90%😭\n请确认车牌号后放行😘"),
            QMessageBox::Yes | QMessageBox::No,
            this
        );
    msgBox2->setDefaultButton(QMessageBox::Yes); // 设置默认按钮
    msgBox2->hide();
}

//=============按钮点击样式===============
void MainWindow::on_up_btn_pressed()
{
   ui->up_btn->setCursor(QCursor(Qt::ClosedHandCursor));
}

void MainWindow::on_down_btn_pressed()
{
    ui->down_btn->setCursor(QCursor(Qt::ClosedHandCursor));
}

void MainWindow::on_up_btn_released()
{
    ui->up_btn->setCursor(QCursor(Qt::OpenHandCursor));
}

void MainWindow::on_down_btn_released()
{
    ui->down_btn->setCursor(QCursor(Qt::OpenHandCursor));
}


//=============udp链接初始化============
void MainWindow::udp_init()
{
    // 初始化UDP socket
    udpSocketVideo1 = new QUdpSocket(this);
    udpSocketVideo2 = new QUdpSocket(this);
    udpSocketPlate1 = new QUdpSocket(this);
    udpSocketPlate2 = new QUdpSocket(this);

    // 绑定端口
    udpSocketVideo1->bind(5000); // 开发板1视频流
    udpSocketVideo2->bind(5001); // 开发板2视频流
    udpSocketPlate1->bind(5010); // 开发板1车牌结果
    udpSocketPlate2->bind(5011); // 开发板2车牌结果

    // 监听端口是否有信息接收
    connect(udpSocketVideo1, &QUdpSocket::readyRead, this,
            &MainWindow::processVideoDatagram1);
    connect(udpSocketVideo2, &QUdpSocket::readyRead, this,
            &MainWindow::processVideoDatagram2);
    connect(udpSocketPlate1, &QUdpSocket::readyRead, this,
            &MainWindow::processPlateDatagram1);
    connect(udpSocketPlate2, &QUdpSocket::readyRead, this,
            &MainWindow::processPlateDatagram2);
}

/*=======================================================================================================================
                                         出、入口视频实现
=========================================================================================================================*/

//入口视频
void MainWindow::processVideoDatagram1() {
  //判断是否有数据  这里一直跑因为
  // 这个while循环只处理已经到达的数据
  // QT的循环事件的机制：数据到达 → 操作系统通知 → QT事件循环 →
  // 触发readyRead信号 → 调用您的槽函数
  while (udpSocketVideo1->hasPendingDatagrams()) {
    // 1. 获取数据包大小并准备缓冲区
    QByteArray datagram;
    datagram.resize(
        udpSocketVideo1->pendingDatagramSize()); //设置这个数组的空间大小和数据包的大小一志
    // 2. 读取数据包    
    udpSocketVideo1->readDatagram(datagram.data(), datagram.size(), &sender1,
                                  &senderPort1);

    // 将数据转换为图像并显示
    // QImage image;
    image1.loadFromData(datagram, "JPEG"); // 将JPEG数据转换为QImage
    if (!image1.isNull()) {
      ui->videoLabel1->setPixmap(
          QPixmap::fromImage(image1).scaled(416, 333, Qt::KeepAspectRatio));
    }
      in_datagram = datagram;  //存储当前图片数据
  }
 // qDebug() << "1"; //这里会一直有1输出  因为这个函数会结束
}

//出口视频
void MainWindow::processVideoDatagram2() {
  while (udpSocketVideo2->hasPendingDatagrams()) {
    QByteArray datagram;

    datagram.resize(udpSocketVideo2->pendingDatagramSize());
    udpSocketVideo2->readDatagram(datagram.data(), datagram.size(), &sender2,
                                  &senderPort2);

    // 将数据转换为图像并显示
    // QImage image;
    image2.loadFromData(datagram, "JPEG");
    if (!image2.isNull()) {
      ui->videoLabel2->setPixmap(
          QPixmap::fromImage(image2).scaled(416, 333, Qt::KeepAspectRatio));
    }
    out_datagram = datagram;   //存储当前图片数据
  }
}

//入口图片
//车牌,卡号,进场时间,准确率
//粤A46Y43,132156465412,2025年8月15日 10:03:01,97.5648
void MainWindow::processPlateDatagram1() {
    if (udpSocketPlate1->hasPendingDatagrams()) {
    //获取的数据字符串
    QByteArray datagram;
    datagram.resize(udpSocketPlate1->pendingDatagramSize());
    QHostAddress sender;
    quint16 senderPort;
    //接收下位机的信息
    udpSocketPlate1->readDatagram(datagram.data(), datagram.size(), &sender,
                                  &senderPort);

    // 处理获取的字符串信息
    QString plateInfo = QString::fromUtf8(datagram);

    qDebug() << "获取数据: " << plateInfo;

    car_id = plateInfo.section(",",0,0);            //车牌号
    card_id = plateInfo.section(",",1,1);           //卡号
    in_time = plateInfo.section(",",2,2);           //进场时间
    accuracy = plateInfo.section(",",3,3);          //确信率
    qDebug() << "确信率: "  << accuracy ;
    current_datagram = in_datagram;

    //显示入场车辆信息
    ui->plateLabel1->setPixmap(
    QPixmap::fromImage(image1).scaled(416, 333, Qt::KeepAspectRatio));   //设置图片
    ui->numberlabel1->setText(car_id);                 //设置入场车牌号显示
    ui->id_edit->setText(car_id);                      //显示车牌
    ui->intime_edit->setText(in_time);                 //显示入场时间
    ui->outtime_edit->setText(NULL);                   //清空离场时间
    ui->card_edit->setText(card_id);                   //显示卡号

    //判断确信率
    float rate = accuracy.toFloat();
    if(rate <= 0.9)
       {
        msgBox->show();
        return;
       }

    QString send_mes=QString("%1,%2").arg(car_id).arg(fee);
    udpSocketPlate1->writeDatagram(send_mes.toUtf8(),(QHostAddress)"192.168.7.73",5000);
    qDebug() << "回发数据:" << car_id << fee;
    qDebug() << sender2.toString();

    //直接将数据添入数据库
    insert(car_id,card_id,in_time,time_calculation(in_time),current_datagram);
    insert2("在场",car_id, card_id, in_time, 0, "", current_datagram, in_time);
    p.record_card(card_id);     //存入卡表

    //刷新图表
    p.refreshInTable();
    p.refreshTotalTable();
    p.show_money(card_id);
    rest_num = total_num - p.current_num;
    ui->total_num->setText(QString::number(total_num));
    ui->rest_num->setText(QString::number(rest_num));
    }
}

//出口图片
//车牌,卡号,离场时间,准确率
void MainWindow::processPlateDatagram2() {
    while (udpSocketPlate2->hasPendingDatagrams()) {
    QByteArray datagram;
    datagram.resize(udpSocketPlate2->pendingDatagramSize());
    QHostAddress sender;
    quint16 senderPort;
    udpSocketPlate2->readDatagram(datagram.data(), datagram.size(), &sender,
                                  &senderPort);

    // 处理车牌识别结果
    QString plateInfo = QString::fromUtf8(datagram);

    car_id = plateInfo.section(",",0,0);            //车牌号
    card_id = plateInfo.section(",",1,1);           //卡号
    out_time = plateInfo.section(",",2,2);          //离场时间
    get_intime = queryInTimeByCarId(car_id);        //入场时间
    accuracy = plateInfo.section(",",3,3);          //确信率
    qDebug() << "确信率: "  << accuracy ;
    current_datagram = out_datagram;

    //显示入场车辆信息
    ui->plateLabel2->setPixmap(
    QPixmap::fromImage(image2).scaled(416, 333, Qt::KeepAspectRatio));  //设置图片
    ui->numberlabel2->setText(car_id);                   //设置入场车牌号显示
    ui->id_edit->setText(car_id);                        //显示车牌
    ui->intime_edit->setText(get_intime);                //显示入场时间
    ui->outtime_edit->setText(out_time);                 //显示离场时间
    ui->card_edit->setText(card_id);                     //显示卡号

    if(time_calculation(get_intime,out_time).toInt()%60!=0)  //停车费用
    {
        fee = (time_calculation(get_intime,out_time).toInt() / 60 + 1) * 4;
    }
    else
    {
       fee = time_calculation(get_intime,out_time).toInt() / 60 * 4;
    }

    //判断确信率
    float rate = accuracy.toFloat();
    if(rate <= 0.9)
       {
            msgBox2->show();
            return;
       }

    QString send_mes=QString("%1,%2").arg(car_id).arg(fee);
    udpSocketPlate2->writeDatagram(send_mes.toUtf8(),(QHostAddress)"192.168.7.175",5001);
    qDebug() << "回发数据:" << car_id << fee;

    //直接将数据添入数据库
    insert2("离场",car_id, card_id, out_time, fee, time_calculation(in_time,out_time) , current_datagram , get_intime);
    p.record_fee(card_id,fee);
    p.del(car_id);
    //刷新图表
    p.refreshInTable();
    p.refreshTotalTable();
    p.show_money(card_id);
    rest_num = total_num - p.current_num;
    ui->rest_num->setText(QString::number(rest_num));
  }
}

/*=======================================================================================================================
                                        存储数据到数据库实现
=========================================================================================================================*/

//计算时间差
QString MainWindow::time_calculation(QString time)
{
    QDateTime local(QDateTime::currentDateTime());
    QString t = local.toString("HH:mm:ss");

    // 定义两个时间字符串
       QString timeStr2 = local.toString("yyyy年MM月dd日 HH:mm:ss");

       QString timeStr1 = time;

       // 定义时间格式
       QString format = "yyyy年MM月dd日 HH:mm:ss";

       // 将字符串转换为QDateTime对象
       QDateTime dateTime1 = QDateTime::fromString(timeStr1, format);
       QDateTime dateTime2 = QDateTime::fromString(timeStr2, format);

       // 检查转换是否成功
       if (!dateTime1.isValid() || !dateTime2.isValid()) {
           qDebug() << "时间格式不正确，转换失败！";
           return NULL;
       }

       // 计算秒数差
       qint64 secondsDiff = dateTime1.secsTo(dateTime2);

       // 转换为分钟
       stay_time = qRound(secondsDiff / 60.0);

       qDebug() << "两个时间相差" << stay_time << "分钟";
       return QString::number(stay_time);
}

QString MainWindow::time_calculation(QString in_time,QString out_time)
{
       // 定义两个时间字符串
       QString timeStr1 = in_time;

       QString timeStr2 = out_time;

       // 定义时间格式
       QString format = "yyyy年MM月dd日 HH:mm:ss";

       // 将字符串转换为QDateTime对象
       QDateTime dateTime1 = QDateTime::fromString(timeStr1, format);
       QDateTime dateTime2 = QDateTime::fromString(timeStr2, format);

       // 检查转换是否成功
       if (!dateTime1.isValid() || !dateTime2.isValid()) {
           qDebug() << "时间格式不正确，转换失败！";
           return NULL;
       }

       // 计算秒数差
       qint64 secondsDiff = dateTime1.secsTo(dateTime2);

       // 转换为分钟
       stay_time = qRound(secondsDiff / 60.0);

       qDebug() << "两个时间相差" << stay_time << "分钟";
       return QString::number(stay_time);
}

//插入incar数据
void MainWindow::insert(const QString& plate, const QString& cardId, const QString& enterTime,
            const QString& parkTime, const QByteArray& pic)
{
    // 检查数据库连接
    if (!db.isOpen()) {
        if (!db.open()) {
            qDebug() << "0数据库连接失败:" ;
            return;
        }
    }

        QSqlQuery query(db);
        QString sql = "INSERT INTO incar ("
                      "车牌, 卡号, 进场时间, 停车时长, 图片"
                      ") VALUES (:plate, :card, :enter, :park, :pic)";

        query.prepare(sql);
        query.bindValue(":plate", plate);       // 车牌
        query.bindValue(":card", cardId);       // 卡号
        query.bindValue(":enter", enterTime);   // 进场时间
        query.bindValue(":park", parkTime);     // 停车时长
        query.bindValue(":pic", pic);           // 图片

        // 执行插入语句
        if (query.exec()) {
            qDebug() << "插入成功（包含BLOB数据）";
            p.refreshInTable();
            p.refreshTotalTable();
        } else {
            qDebug() << "插入失败：" ;
        }
}

//插入totalcar数据
void MainWindow::insert2(const QString& status,const QString& plate, const QString& cardId, const QString& time, int fee,
                         const QString& parkTime, const QByteArray& pic, const QString& intime)
{
    // 检查数据库连接
    if (!db.isOpen()) {
        if (!db.open()) {
            qDebug() << "数据库连接失败0";
            return;
        }
    }
        QSqlQuery query(db);
        QString sql = "INSERT INTO totalcar ("
                      "状态, 车牌, 卡号, 时间, 费用, 停车时长, 图片, 进场时间"
                      ") VALUES (:status, :plate, :card, :time, :fee, :park, :pic, :intime)";

        // 绑定参数
        query.prepare(sql);
        query.bindValue(":status", status);     // 状态
        query.bindValue(":plate", plate);       // 车牌
        query.bindValue(":card", cardId);       // 卡号
        query.bindValue(":time", time);         // 进场时间
        query.bindValue(":fee", fee);           // 费用
        query.bindValue(":park", parkTime);     // 停车时长
        query.bindValue(":pic", pic);           // 图片
        query.bindValue(":intime", intime);     // 停车时长

        //执行插入语句
        if (query.exec()) {
            qDebug() << "插入成功（包含BLOB数据）";
            p.refreshInTable();
            p.refreshTotalTable();
        } else {
            qDebug() << "插入失败：" ;
        }
}


//通过车牌查询入场时间
QString MainWindow::queryInTimeByCarId(const QString& carId) {    
     QSqlQuery query(db);
    //从incar表中根据车牌查询入场时间
    query.prepare("SELECT 进场时间 FROM incar WHERE 车牌 = :carId");
    query.bindValue(":carId", carId);

    if (query.exec()) {
        if (query.next()) { // 找到匹配记录
            return query.value(0).toString();
        } else {
            qDebug() << "未找到车牌为" << carId << "的入场记录";
            return ""; // 无记录时返回空字符串
        }
    } else {
        qDebug() << "查询入场时间失败" ;
        return "";
    }
}


//判断弹窗点击事件
//发送 warm: / warm:
void MainWindow::warm(QAbstractButton *button)
{
        // 获取消息框的标准按钮
        QMessageBox *msgBox = qobject_cast<QMessageBox*>(sender());
        if (!msgBox) return;

        // 判断点击的是哪个按钮
        if (msgBox->standardButton(button) == QMessageBox::Yes) {
            qDebug() << "点击了Yes按钮";

            QString send_mes=QString("%1,%2").arg(car_id).arg(fee);
            //回发车牌到下位机
            udpSocketPlate2->writeDatagram(send_mes.toUtf8(),(QHostAddress)"192.168.7.175",5001);
            qDebug() << "回发数据:" << car_id << fee;

            //直接将数据添入数据库
            insert2("离场",car_id, card_id, out_time, fee, time_calculation(in_time,out_time) , current_datagram,get_intime);
            p.record_fee(card_id,fee);
            p.del(car_id);
            //刷新图表
            p.refreshInTable();
            p.refreshTotalTable();
            p.show_money(card_id);
            rest_num = total_num - p.current_num;
            ui->rest_num->setText(QString::number(rest_num));

        } else if (msgBox->standardButton(button) == QMessageBox::No) {
            qDebug() << "点击了No按钮";
            index=2;
            msgBox->hide();
            return;
        }
}

//判断弹窗点击事件
//发送 warm: / warm:
void MainWindow::warm2(QAbstractButton *button)
{
        // 获取消息框的标准按钮
        QMessageBox *msgBox = qobject_cast<QMessageBox*>(sender());
        if (!msgBox) return;

        // 判断点击的是哪个按钮
        if (msgBox->standardButton(button) == QMessageBox::Yes) {
            qDebug() << "点击了Yes按钮";

            QString send_mes=QString("%1,%2").arg(car_id).arg(fee);
            //回发车牌到下位机
            udpSocketPlate1->writeDatagram(send_mes.toUtf8(),(QHostAddress)"192.168.7.73",5000);
            qDebug() << "回发数据:" << car_id << fee;

            //直接将数据添入数据库
            insert(car_id,card_id,in_time,time_calculation(in_time),current_datagram);
            insert2("在场",car_id, card_id, in_time, 0, "", current_datagram,in_time);
            p.record_card(card_id);     //存入卡表
            //刷新图表
            p.refreshInTable();
            p.refreshTotalTable();
            p.show_money(card_id);
            rest_num = total_num - p.current_num;
            ui->rest_num->setText(QString::number(rest_num));
        } else if (msgBox->standardButton(button) == QMessageBox::No) {
            qDebug() << "点击了No按钮";
            index=1;
            msgBox->hide();
            return;
        }
}

//改正信息后抬杆
void MainWindow::on_up_btn_clicked()
{
    if(index == 1)
    {
    car_id = ui->numberlabel1->text();

    QString send_mes=QString("%1,%2").arg(car_id).arg(fee);
    //回发车牌到下位机
    udpSocketPlate1->writeDatagram(send_mes.toUtf8(),(QHostAddress)"192.168.7.73",5000);
    qDebug() << "回发数据:" << car_id << fee;

    insert(car_id,card_id,in_time,time_calculation(in_time),current_datagram);
    insert2("在场",car_id, card_id, in_time, 0, "", current_datagram,in_time);
    p.record_card(card_id);     //存入卡表
    p.refreshInTable();
    p.refreshTotalTable();
    p.show_money(card_id);
    ui->id_edit->setText(car_id);
    rest_num = total_num - p.current_num;
    ui->rest_num->setText(QString::number(rest_num));
    }
    if(index == 2)
    {
        car_id = ui->numberlabel2->text();

        QString send_mes=QString("%1,%2").arg(car_id).arg(fee);
        //回发车牌到下位机
        udpSocketPlate2->writeDatagram(send_mes.toUtf8(),(QHostAddress)"192.168.7.175",5001);
        qDebug() << "回发数据:" << car_id << fee;

        insert2("离场",car_id, card_id, out_time, fee, time_calculation(in_time,out_time) , current_datagram,get_intime);
        p.record_fee(card_id,fee);
        p.del(car_id);
        p.refreshInTable();
        p.refreshTotalTable();
        p.show_money(card_id);
        ui->id_edit->setText(car_id);
        rest_num = total_num - p.current_num;
        ui->rest_num->setText(QString::number(rest_num));
    }
}




